﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Imaging;
using System.Drawing;

namespace Team6_Algorithms.Filters
{
    public class CombinedMasking
    {
        public static int RedMean;
        public static int GreenMean;
        public static int BlueMean;

        /// <summary>
        /// Made by Dylan Snel
        /// Filter that combines a list of masks
        /// And returns either the mean of the filters or the Max value
        /// </summary>
        /// <param name="B">the Source Image</param>
        /// <param name="MASK">List containing the masks</param>
        /// <param name="MAX">If true, returns the max value instead of the mean.</param>
        /// <returns>wheter the script ran succesfull</returns>
        public static bool applyFilter(Bitmap B, List<Mask> MASK, bool MAX)
        {



            Bitmap bSrc = (Bitmap)B.Clone();

            BitmapData BmData = B.LockBits(new Rectangle(0, 0, B.Width, B.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData BmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            int stride = BmData.Stride;

            System.IntPtr Scan0 = BmData.Scan0;
            System.IntPtr SrcScan0 = BmSrc.Scan0;

            unsafe
            {
                byte* p = (byte*)(void*)Scan0;
                byte* pSrc = (byte*)(void*)SrcScan0;

                p += ((MASK[0].Size - 1) / 2) * stride;
                p += ((MASK[0].Size - 1) / 2) * 3;
                pSrc += ((MASK[0].Size - 1) / 2) * stride;
                pSrc += ((MASK[0].Size - 1) / 2) * 3;

                int nOffset = B.Width % 4;
                int nWidth = B.Width - MASK[0].Size + 1;
                int nHeight = B.Height - MASK[0].Size + 1;

                for (int y = 0; y < nHeight; ++y)
                {
                    for (int x = 0; x < nWidth; ++x)
                    {
                        int TempRed=0, TempGreen=0, TempBlue=0;
                        int[] RedValues = new int[MASK.Count];
                        int[] GreenValues = new int[MASK.Count];
                        int[] BlueValues = new int[MASK.Count];
                        int i = 0;
                        foreach (Mask m in MASK)
                        {

                            calculateMeans(pSrc, m, stride);
                            TempRed += RedMean;
                            TempGreen += GreenMean;
                            TempBlue += BlueMean;
                            RedValues[i] = RedMean;
                            GreenValues[i] = GreenMean;
                            BlueValues[i] = BlueMean;
                            i++;
                        }
                        if (MAX == false)
                        {
                            RedMean = TempRed / MASK.Count;
                            GreenMean = TempGreen / MASK.Count;
                            BlueMean = TempBlue / MASK.Count;
                            p[0] = (byte)BlueMean;
                            p[1] = (byte)GreenMean;
                            p[2] = (byte)RedMean;
                        }
                        else
                        {
                            p[0] = (byte)BlueValues.Max();
                            p[1] = (byte)GreenValues.Max();
                            p[2] = (byte)RedValues.Max();
                        }
                        p += 3;
                        // add 3 pixels to the address? possibly
                        // at least, this is moving through the pic
                        // or maybe 3 bytes
                        pSrc += 3;
                    }
                    // but then here we add the padding... at the end of every row
                    pSrc += -3 + ((MASK[0].Size - 1) / 2) * 3;
                    p += -3+ ((MASK[0].Size - 1) / 2) * 3;
                    p += nOffset;
                    pSrc += nOffset;
                }
            }

            B.UnlockBits(BmData);
            bSrc.UnlockBits(BmSrc);

            return true;
        }

        
        /// <summary>
        /// Private function used to calculate the value of a mask
        /// </summary>
        /// <param name="P">pointer to Scan0 of the source bitmap</param>
        /// <param name="MASK"></param>
        /// <param name="STRIDE"></param>
        private static unsafe void calculateMeans(byte* P, Mask MASK, int STRIDE)
        {
            RedMean = 0;
            GreenMean = 0;
            BlueMean = 0;
            int yCounter = 0;
            int xCounter = 0;
            byte* CalcPointer = P;
            int Boundary = (MASK.Size - 1) / 2;
            for (int y = -Boundary; y <= Boundary; ++y)
            {

                for (int x = -Boundary; x <= Boundary; ++x)
                {
                    RedMean += CalcPointer[2 + (x * 3) + (y * STRIDE)] * MASK.MaskValues[xCounter][yCounter];
                    GreenMean += CalcPointer[1 + (x * 3) + (y * STRIDE)] * MASK.MaskValues[xCounter][yCounter];
                    BlueMean += CalcPointer[0 + (x * 3) + (y * STRIDE)] * MASK.MaskValues[xCounter][yCounter];

                    xCounter++;

                }
                xCounter = 0;
                yCounter++;
            }
            RedMean /= MASK.Total;
            GreenMean /= MASK.Total;
            BlueMean /= MASK.Total;

            RedMean += MASK.OffSet;
            GreenMean += MASK.OffSet;
            BlueMean += MASK.OffSet;
            if (RedMean > 255)
            {
                RedMean = 255;
            }
            if (GreenMean > 255)
            {
                GreenMean = 255;
            }
            if (BlueMean > 255)
            {
                BlueMean = 255;
            }
            if (RedMean < 0)
            {
                RedMean = 0;
            }
            if (GreenMean < 0)
            {
                GreenMean = 0;
            }
            if (BlueMean < 0)
            {
                BlueMean = 0;
            }



        }

    }

}